﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using Telerik.Windows.Controls;
using Timetable.AWP.Host.Tutorial;
using Course = Timetable.AWP.Host.Course.Course;
using DayOfWeek = Timetable.AWP.Models.DayOfWeek;
using Faculty = Timetable.AWP.Host.Faculty.Faculty;
using Group = Timetable.AWP.Host.Group.Group;
using Lecturer = Timetable.AWP.Host.Lecturer.Lecturer;
using TutorialType = Timetable.AWP.Host.TutorialType.TutorialType;
using Time = Timetable.AWP.Host.Time.Time;

namespace Timetable.AWP.ViewModels
{
    internal sealed class ScheduleEditor: BaseViewModel
    {
        #region Faculty
        private IEnumerable<Faculty> _faculties;
        public IEnumerable<Faculty> Faculties
        {
            get { return _faculties; }
            set
            {
                _faculties = value;
                OnPropertyChanged("Faculties");
            }
        }

        private Faculty _selectedFaculty;
        public Faculty SelectedFaculty
        {
            get { return _selectedFaculty; }
            set
            {
                _selectedFaculty = value;
                OnPropertyChanged("SelectedFaculty");

                //if (value != null) LoadSpecialities();
                if (value != null && SelectedCourse != null) LoadGroups();
            }
        }
        #endregion

        #region Course
        private IEnumerable<Course> _courses;
        public IEnumerable<Course> Courses
        {
            get { return _courses; }
            set
            {
                _courses = value;
                OnPropertyChanged("Courses");
            }
        }

        private Course _selectedCourse;
        public Course SelectedCourse
        {
            get { return _selectedCourse; }
            set 
            { 
                _selectedCourse = value;
                OnPropertyChanged("SelectedCourse");
                OnPropertyChanged("IsEnabledSpecialities");

                if(value != null && SelectedFaculty != null)
                {
                    LoadGroups();
                    LoadTutorialsForCourse();
                    //LoadScheduleForCourse();
                }
            }
        }
        #endregion
        
        #region Group
        private IEnumerable<Selector<Group>> _groups;
        public IEnumerable<Selector<Group>> Groups
        {
            get { return _groups; }
            set
            {
                _groups = value;
                OnPropertyChanged("Groups");
                OnPropertyChanged("IsEnabledGroups");
            }
        }

        #endregion

        #region Tutorial

        private IEnumerable<Tutorial> _tutorials;
        public IEnumerable<Tutorial> Tutorials
        {
            get { return _tutorials; }
            set 
            {
                _tutorials = value;
                OnPropertyChanged("Tutorials");
                OnPropertyChanged("IsEnabledTutorials");
            }
        }

        private Tutorial _selectedTutorial;
        public Tutorial SelectedTutorial
        {
            get { return _selectedTutorial; }
            set
            {
                _selectedTutorial = value;
                OnPropertyChanged("SelectedTutorial");
                if (_selectedTutorial != null)
                {
                    LoadLecturers();
                    LoadTutorialTypes();
                }
            }
        }
        #endregion

        #region Tutorial Type

        private IEnumerable<TutorialType> _tutorialTypes;
        public IEnumerable<TutorialType> TutorialTypes
        {
            get { return _tutorialTypes; }
            set 
            {
                _tutorialTypes = value;
                OnPropertyChanged("TutorialTypes");
                OnPropertyChanged("IsEnabledTutorialTypes");
            }
        }

        private TutorialType _selectedTutorialType;
        public TutorialType SelectedTutorialType
        {
            get { return _selectedTutorialType; }
            set
            {
                _selectedTutorialType = value;
                OnPropertyChanged("SelectedTutorialType");

                if(_selectedTutorialType != null)
                    LoadLecturers();
            }
        }

        #endregion

        #region Lecturer

        private IEnumerable<Lecturer> _lecturers;
        public IEnumerable<Lecturer> Lecturers
        {
            get { return _lecturers; }
            set
            {
                _lecturers = value;
                OnPropertyChanged("Lecturers");
                OnPropertyChanged("IsEnabledLecturers");
            }
        }

        private Lecturer _selectedLecturer;
        public Lecturer SelectedLecturer
        {
            get { return _selectedLecturer; }
            set 
            { 
                _selectedLecturer = value;
                OnPropertyChanged("SelectedLecturer");
            }
        }

        #endregion

        #region Enabled detectors

        public bool IsEnabledGroups
        {
            get { return Groups != null && Groups.Any(); }
        }

        public bool IsEnabledTutorials
        {
            get { return Tutorials != null && Tutorials.Any(); }
        }

        public bool IsEnabledTutorialTypes
        {
            get { return TutorialTypes != null && TutorialTypes.Any(); }
        }

        public bool IsEnabledLecturers
        {
            get { return Lecturers != null && Lecturers.Any(); }
        }
        #endregion

        #region Time

        private IEnumerable<Time> _times;
        public IEnumerable<Time> Times
        {
            get { return _times; }
            set
            {
                _times = value;
                OnPropertyChanged("Times");
            }
        }

        public Time SelectedTime { get; set; }
        #endregion

        #region Day

        private IEnumerable<Selector<DayOfWeek>> _days;
        public IEnumerable<Selector<DayOfWeek>> Days
        {
            get { return _days; }
            set 
            { 
                _days = value;
                OnPropertyChanged("Days");
            }
        }

        #endregion

        #region Schedule

        public static DependencyProperty GroupSchedulesProperty;
        public ObservableCollection<Host.Schedule.Schedule> GroupsSchedule
        {
            get { return GetValue(GroupSchedulesProperty) as ObservableCollection<Host.Schedule.Schedule>; }
            set
            {
                var oldValue = GetValue(GroupSchedulesProperty);
                SetValue(GroupSchedulesProperty, value);
                OnPropertyChanged(new DependencyPropertyChangedEventArgs(GroupSchedulesProperty, oldValue, value));
            }
        }

        //public static readonly RoutedEvent GroupsScheduleChangedEvent =
        //    EventManager.RegisterRoutedEvent("GroupsScheduleChanged",
        //        RoutingStrategy.Bubble,
        //        typeof(RoutedPropertyChangedEventHandler<ObservableCollection<Host.Schedule.Schedule>>),
        //        typeof(ScheduleEditor));
        

        #endregion

        #region ScheduleInfo

        private ObservableCollection<Host.ScheduleInfo.ScheduleInfo> _groupScheduleInfos;
        public ObservableCollection<Host.ScheduleInfo.ScheduleInfo> GroupScheduleInfos
        {
            get { return _groupScheduleInfos; }
            set 
            { 
                _groupScheduleInfos = value;
                OnPropertyChanged("SelectedFaculty");
            }
        }

        #endregion

        public ScheduleEditor()
        {
            Faculties = FacultyService.GetAll();
            Courses = CourseService.GetAll();
            Times = TimeService.GetAll();
            Days = new List<Selector<DayOfWeek>>
                       {
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 1, Name = "Понедельник"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 2, Name = "Вторник"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 3, Name = "Среда"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 4, Name = "Четверг"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 5, Name = "Пятница"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 6, Name = "Суббота"},
                               },
                           new Selector<DayOfWeek>
                               {
                                   Object = new DayOfWeek {Id = 7, Name = "Воскресенье"},
                               },
                       };
           GroupSchedulesProperty = Schedule.GroupSchedulesProperty.AddOwner(typeof(ScheduleEditor));
        }

        #region Private methods
        private void LoadGroups()
        {
            var groups = GroupService.GetAll(SelectedFaculty.Id, SelectedCourse.Id);
            Groups = groups.Select(
                @group => new Selector<Group>
                              {
                                  Object = @group, 
                                  SelectCallback = () =>
                                                       {
                                                           if (Groups.Any(x => x.IsSelected))
                                                           {
                                                               LoadTutorialsForGroups();
                                                               LoadScheduleForGroups();
                                                               LoadScheduleInfoForGroups();
                                                           }
                                                           else
                                                               LoadTutorialsForCourse();
                                                       }
                              }).ToList();
        }

        private void LoadTutorialsForCourse()
        {
            Tutorials = TutorialService.GetAllForCourse(SelectedFaculty.Id, SelectedCourse.Id);
            SelectedLecturer = null;
            SelectedTutorialType = null;
        }

        private void LoadTutorialsForGroups()
        {
            var neededGroupIds = Groups.Where(x => x.IsSelected).Select(x => (x.Object as Group).Id);
            var tutorials = new List<Tutorial>();
            foreach (int neededGroupId in neededGroupIds)
            {
                tutorials.AddRange(
                    TutorialService.GetAllForGroup(SelectedFaculty.Id, SelectedCourse.Id, neededGroupId));
            }

            Tutorials = tutorials;

            SelectedLecturer = null;
            SelectedTutorialType = null;
        }

        private void LoadLecturers()
        {
            if (SelectedTutorialType != null && SelectedTutorialType.Id > 0)
                Lecturers = LecturerService.GetAllForTutorialAndTutorialType(SelectedTutorial.Id, SelectedTutorialType.Id);
            else
                Lecturers = LecturerService.GetAllForTutorial(SelectedTutorial.Id);
        }

        private void LoadTutorialTypes()
        {
            TutorialTypes = TutorialTypeService.GetAll();
        }

        private void LoadScheduleForGroups()
        {
            var groups = Groups.Where(x => x.IsSelected);
            var result = new ObservableCollection<Host.Schedule.Schedule>();
            foreach (var group in groups)
            {
                result.AddRange(
                    ScheduleService.GetAllForGroup(
                        SelectedFaculty.Id,
                        SelectedCourse.Id,
                        group.Object.Id));
            }

            GroupsSchedule = result;
        }

        private void LoadScheduleInfoForGroups()
        {
            var groups = Groups.Where(x => x.IsSelected);
            var result = new ObservableCollection<Host.ScheduleInfo.ScheduleInfo>();
            foreach (var @group in groups)
            {
                result.AddRange(
                    ScheduleInfoService.GetAllForGroup(
                        SelectedFaculty.Id,
                        SelectedCourse.Id,
                        group.Object.Id));
            }

            GroupScheduleInfos = result;
        }

        #endregion


        public class Selector<T> : INotifyPropertyChanged
        {
            public T Object { get; set; }

            private bool _isSelected;
            public bool IsSelected
            {
                get { return _isSelected; }
                set
                {
                    _isSelected = value;

                    if (SelectCallback != null)
                        SelectCallback();

                    OnPropertyChanged("IsSelected");
                }
            }

            public Action SelectCallback;

            public void Unselect()
            {
                OnPropertyChanged("IsSelected");
                _isSelected = false;
            }

            public void Select()
            {
                OnPropertyChanged("IsSelected");
                _isSelected = true;
            }

            public event PropertyChangedEventHandler PropertyChanged;

            protected void OnPropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
